home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 52
/
Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso
/
Aminet
/
misc
/
emu
/
Apex-src.lha
/
LOAD.XPL
< prev
next >
Wrap
Text File
|
2001-09-30
|
13KB
|
449 lines
\LOAD.XPL JUL-07-88
\Loader for .OBJ files
\Written by Loren Blaney for DFM Engineering
\REVISION HISTORY:
\FEB-17-86, Original
\MAY-01-86, Modified to load assembly files
\OCT-12-86, Option to load anywhere, and modified for new system.
\DEC-12-86, Major clean up, added multiple file capability.
\FEB-02-87, Allow multiple file names to be in lowercase, and
\ use START vector to determine if .68K code set up SYSPAG parameters.
\APR-10-87, Change string conventions
\JUL-07-88, Change default load location (from $3000 to $1000), set default
\ heap and stack, change range conventions so that the maximum address now
\ includes the end point.
\
\NOTES:
\This program loads and (optionally) starts the .OBJ file which is
\ produced by either the compiler or the assembler. This loader combines
\ the capabilities of the following programs which run on the Apple:
\ LOAD, the loader in I2L, LODBX, LODIX, SXLOD, and SYSLOD.
\
\Loading this loader is a two-step process: Use the existing loader to
\ load the new loader at $1000, and make a .SAV file of this temporary
\ loader (LOADX). Now use the temporary loader to load the new loader at
\ $76800. This temporary loader is also used to load APEX.OBJ.
code
ABS=0, RAN=1, REM=2, RESERVE=3,
SWAP=4, EXTEND=5, RESTART=6, CHIN=7,
CHOUT=8, CRLF=9, INTIN=10, INTOUT=11,
TEXT=12, OPENI=13, OPENO=14, CLOSE=15,
ABORT=16, SCAN=24, HEXIN=26, HEXOUT=27,
OPENF=29;
ext CHIN3=$C00;
int CHAR, \Character read from disk
CHARKB, \Character read from keyboard
MINADDR, \Minimum address at execution time
MAXADDR, \Maximum address +1 at execution time
OFFSET, \Offset to add to go from execution to load address
DEFAULT, \Array of default settings
VSTARTX, \SYSPAG JMP vector to start of loaded program
LINKPTR, \Pointer to 'LINK' jump table
LINEPTR; \Pointer (index) into LINEBUF
addr BASEADDR, \Execution base address of current module (also @)
LOADADDR, \Load base address (@ + OFFSET)
FIRSTBASE, \Execution base address of first module
FIRSTLOAD, \Load base address of first module
LINEBUF; \Line buffer: holds copy of keyboard buffer
reg int PC; \The current load address (relative to BASEADDR)
def TV=0, KB=0;
def BEL=$07, CR=$0D, EOF=$1A, SP=$20;
def INTSIZE=4; \Number of bytes in an integer
\----------------------------------------------------------------------\
func GETCH; \Get next character from LINEBUF
int CH;
begin
CH:= LINEBUF(LINEPTR);
if CH >= ^a & CH <= ^z then CH:= CH & $DF; \Convert to upper case
LINEPTR:= LINEPTR +1;
return CH;
end; \GETCH
proc ERROR(STR); \Display error message and abort
addr STR;
begin
TEXT(TV,"
OH OH - ");
CHOUT(TV,BEL);
TEXT(TV,STR);
CRLF(TV);
ABORT;
end; \ERROR
\----------------------------------------------------------------------\
func HEXBYTE; \Read in 2 chars and return the value of the hex byte
reg int CH, HEX; \ (Optimized for speed)
begin
loop begin
CH:= CHAR;
if CH <= ^9 then
if CH >= ^0 then [HEX:= (CH -^0) <<4; quit];
if CH >= ^A then
if CH <= ^F then [HEX:= (CH -$37) <<4; quit];
ERROR("HEX CHARACTER EXPECTED"); \(never returns)
end;
CH:= CHIN3;
CHAR:= CHIN3;
if CH <= ^9 then
if CH >= ^0 then return HEX + CH -^0;
if CH >= ^A then
if CH <= ^F then return HEX + CH -$37;
ERROR("HEX CHARACTER EXPECTED");
end; \HEXBYTE
func HEXWORD; \Read in 4 chars and return the value of the hex word
return SWAP(HEXBYTE) + HEXBYTE;
func HEXLONG; \Read in 8 chars and return the value of the hex long word
return HEXWORD <<16 + HEXWORD;
\----------------------------------------------------------------------
proc STOBYTE(BYTE); \Store a byte at the current load address
int BYTE;
reg int I;
begin
\Strip out any bytes that are outside the load range:
I:= PC + BASEADDR;
if I >= MAXADDR then [CHOUT(TV,^+); return];
if I < MINADDR then [CHOUT(TV,^-); return];
LOADADDR(PC):= BYTE;
PC:= PC +1;
end; \STOBYTE
\----------------------------------------------------------------------
proc GETPC; \(;) Read in a relative load address
\A 4-digit base-relative address follows the ";". The base-relative PC is
\ set to this value.
begin
PC:= HEXWORD;
end; \GETPC
proc GETFIXED; \(^) Fix a forward reference
\A 4-digit base-relative address follows the "^". The contents at this address
\ must be changed to point to the current PC value (using relative addressing).
int ADDR, \Base-relative address whos contents need "fixing"
RELADDR; \Relative address value pointing forward to current PC
begin
ADDR:= HEXWORD;
RELADDR:= PC -ADDR;
LOADADDR(ADDR):= SWAP(RELADDR);
LOADADDR(ADDR+1):= RELADDR;
end; \GETFIXED
proc GETABS; \(*) Relocate an absolute address
\An 8-digit, base-relative address follows the "*". The value of this address
\ must be changed to its equivalent absolute execution address. This is only
\ used for multi-dimensional, constant arrays.
int ADDR; \Base-relative address to be converted to absolute addr
addr A;
begin
ADDR:= HEXLONG; \Get the 8-digit, base-relative addr
ADDR:= ADDR + BASEADDR; \Convert to absolute execution address
A:= addr ADDR; \Access the individual bytes of ADDR
STOBYTE(A(0)); \Load them, MSB first
STOBYTE(A(1));
STOBYTE(A(2));
STOBYTE(A(3));
end; \GETABS
proc GETBASE; \(@) Read in a base address
\An 8-digit absolute address follows the "@". The base address is
\ set to this value.
begin
BASEADDR:= HEXLONG;
LOADADDR:= BASEADDR + OFFSET; \Convert to load address
PC:= 0;
end; \GETBASE
proc GETABS2; \(#) Relocate an absolute address
\An 8-digit, base-relative address follows the "#". The value of this address
\ must be changed to its equivalent absolute execution address. This is only
\ used for jumping to linked procedures in external modules.
int ADDR; \Base-relative address to be converted to absolute addr
addr A;
begin
ADDR:= HEXLONG; \Get the 8-digit, base-relative addr
ADDR:= ADDR + FIRSTBASE; \Convert to absolute execution address
A:= addr ADDR; \Access the individual bytes of ADDR
STOBYTE(A(0)); \Load them, MSB first
STOBYTE(A(1));
STOBYTE(A(2));
STOBYTE(A(3));
end; \GETABS2
proc GETLINKED; \(%) Link an external procedure
\The next entry in the external procedure jump table is set to point to the
\ current absolute address. There must be a one-to-one correspondance between
\ external procedure declarations (#) and linked procedures (%) otherwise
\ the load image will be corrupted without warning.
begin
LINKPTR(0):= PC + BASEADDR - OFFSET; \Store absolute address at link pointer
LINKPTR:= LINKPTR +6; \Point to next entry in jump table
end; \GETLINKED
\----------------------------------------------------------------------
proc GETKBBUF; \Get the keyboard buffer into LINEBUF
\Since we may be loading more than one file and the keyboard buffer is
\ used for obtaining defaults, we must save the keyboard buffer in LINEBUF.
\Apex has read and set up the first file name, and it read the file name's
\ terminator. We must back up to see if the terminator was a CR.
int CH,
LINPTRF, \Keyboard buffer pointers on SYSPAG
LINPTRE;
begin
LINPTRF:= $690;
LINPTRE:= $694;
LINEPTR:= 0;
if LINPTRF(0) = LINPTRE(0) then \The KB buffer is empty, stuff CR
LINEBUF(LINEPTR):= CR
else begin \Read the KB buffer into LINEBUF
loop begin
CH:= CHIN(KB);
LINEBUF(LINEPTR):= CH;
if CH = CR then quit;
if LINEPTR > 255 then ERROR("TOO MANY FILE NAMES");
LINEPTR:= LINEPTR +1;
end;
end;
LINEPTR:= 0;
end; \GETKBBUF
proc DOINCL; \Include another .OBJ file
int BLK; \Array: for SCAN
addr NAME, \Array: holds file name
IDENT; \Array: holds identifier name (file name or ext)
int INUNIT; \Input unit number
proc GETIDENT; \Get an identifier name and return it in IDENT
int LEN;
begin
IDENT(0):= CHARKB;
CHARKB:= GETCH;
LEN:= 1;
loop case of
CHARKB>=^A & CHARKB<=^Z, CHARKB>=^0 & CHARKB<=^9, CHARKB=^_ :
begin
if LEN < 8 then
begin
IDENT(LEN):= CHARKB;
LEN:= LEN +1;
end;
CHARKB:= GETCH;
end
other quit;
for LEN:= LEN,7 do IDENT(LEN):= SP;
end; \GETIDENT
proc GETNAME; \Get name & unit of include file
int I;
addr INUNT;
begin
INUNT:= $56C;
INUNIT:= INUNT(0); \Get the default input unit number
NAME(8):= ^O; NAME(9):= ^B; NAME(10):= ^J; \Default extension
if CHARKB>=^0 & CHARKB<=^9 then
begin \We have an explicit unit number
INUNIT:= CHARKB & $0F;
CHARKB:= GETCH; \Skip unit number
if CHARKB#^: then ERROR("^":^" EXPECTED");
CHARKB:= GETCH; \Skip the colon
end;
GETIDENT;
for I:=0,7 do NAME(I):= IDENT(I);
if CHARKB=^. then
begin \We have an explicit extension
CHARKB:= GETCH; \Skip the "."
GETIDENT;
for I:=0,2 do NAME(I+8):= IDENT(I);
end;
end; \GETNAME
proc STROUT(STR, SIZE); \Output string to TV
addr STR;
int SIZE;
int I;
begin
for I:= 0, SIZE-1 do
CHOUT(TV, STR(I));
end; \STROUT
begin \DOINCL
NAME:= RESERVE(11);
IDENT:= RESERVE(8);
BLK:= RESERVE(2 *INTSIZE);
GETNAME; \Get the file's name
SCAN(INUNIT, BLK, NAME); \Get its first and last blocks
OPENF(INUNIT, BLK);
\Show the name of the inculded file:
TEXT(TV,"
INCLUDING: ");
INTOUT(TV,INUNIT); CHOUT(TV,^:);
STROUT(NAME,8); CHOUT(TV,^.); STROUT(NAME+8,3);
end; \DOINCL
\----------------------------------------------------------------------
proc STARTUP;
\Set up system page parameters and optionally start the program.
\This procedure never returns.
int USRMEM, \Base address of user program (variable in SYSPAG)
VRSTRTX, \Entry point for a restart (variable in SYSPAG)
PROSIZ, \User program size (VARIABLE IN SYSPAG)
HEAP, \Base address of loaded program's heap space
STACK; \Start of stack space (grows downward)
ext VSTART=$400; \Start vector
begin
if VSTARTX(0) = -1 then \Assume XPL code was loaded and
begin \ set up the SYSPAG variables
VRSTRTX:= $408;
USRMEM:= $432;
PROSIZ:= $436;
HEAP:= $46E;
STACK:= $472;
VSTARTX(0):= FIRSTLOAD;
VRSTRTX(0):= FIRSTLOAD;
USRMEM(0):= FIRSTLOAD;
\Program size in blocks: (one byte too big but beware of PC = 0)
PROSIZ(0):= (PC +BASEADDR -FIRSTBASE) /256 +1;
HEAP(0):= (BASEADDR +PC +1 ) &$FFFFFFFE; \(use word boundary)
STACK(0):= MAXADDR & $FFFFFFFE;
end;
TEXT(TV,"
PRESS ^"RETURN^" TO EXECUTE (OR CTRL-P TO SAVE) ");
OPENI(KB);
if CHIN(KB) then; \Wait for RETURN key
\If LOADADDR # BASEADDR (i.e. if OFFSET # 0) then he shouldn't be doing this.
\The user's XPL program will use the loader's SYSPAG parameters, heap space,
\ and there will be no disk I/O (device #3).
VSTART;
exit;
end; \STARTUP
\----------------------------------------------------------------------
begin \MAIN
LINEBUF:= RESERVE(256);
TEXT(TV,"-- .OBJ LOADER, V1.0x12 --
");
GETKBBUF;
CHARKB:= GETCH;
DEFAULT:= [$1000, $0000, $1FFFF, $0000]; \BASE, MIN, MAX, LOAD
loop begin
TEXT(TV,"CHANGE DEFAULTS (N/Y)? ");
if (CHIN(KB) ! $20) # ^y then quit;
TEXT(TV,"XPL EXECUTION BASE ADDRESS? $");
DEFAULT(0):= HEXIN(KB);
TEXT(TV,"MINIMUM EXECUTION ADDRESS? $");
DEFAULT(1):= HEXIN(KB);
TEXT(TV,"MAXIMUM EXECUTION ADDRESS? $");
DEFAULT(2):= HEXIN(KB);
TEXT(TV,"LOAD LOCATION OF MINIMUM ADDRESS? $");
DEFAULT(3):= HEXIN(KB);
end;
BASEADDR:= DEFAULT(0);
MINADDR:= DEFAULT(1);
MAXADDR:= DEFAULT(2) +1;
OFFSET:= DEFAULT(3) - MINADDR;
LOADADDR:= BASEADDR + OFFSET;
FIRSTBASE:= BASEADDR;
FIRSTLOAD:= LOADADDR;
LINKPTR:= LOADADDR +6; \Point to first entry in 'LINK' jump table
\Set VSTARTX to an illegal address. This location must be altered. Either
\ a loaded .68K program will do it, or STARTUP will. If STARTUP does it,
\ it will also set up some other SYSPAG parameters.
VSTARTX:= $402;
VSTARTX(0):= -1; \(Will cause an address error)
OPENI(3);
TEXT(TV,"LOADING...");
loop begin
PC:= 0;
CHAR:= CHIN3; \One character look ahead
loop begin
case CHAR of
^;: [CHAR:= CHIN3; GETPC];
^^: [CHAR:= CHIN3; GETFIXED];
^*: [CHAR:= CHIN3; GETABS];
^@: [CHAR:= CHIN3; GETBASE];
^#: [CHAR:= CHIN3; GETABS2];
^%: [CHAR:= CHIN3; GETLINKED];
EOF: quit
other STOBYTE(HEXBYTE);
end;
while CHARKB=^, ! CHARKB=SP do CHARKB:= GETCH;
if CHARKB = CR then quit; \KB buffer is empty
DOINCL; \Include next file
BASEADDR:= BASEADDR +PC;
LOADADDR:= BASEADDR + OFFSET;
end;
STARTUP;
end; \MAIN
y
DOINCL; \Include next file
BASEADDR:= BASEADDR +PC;
LOADADDR:= BASEADDR + OFFSET;
end;
STARTUP;